//慎用！！！！
//定时器中断例子，简单的频率计
//效果：将P13与P17用单片线连接起来，数码管上显示相应的测试频率，做外测试时，请留意各引脚电压极性和电压值，
//		不可超出5V，只做学习实验，最好不要超出板子范围
//头文件
#include "reg51.h"

/********IO引脚定义***********************************************************/
sbit Fin=P1^3;    		//测量频率管脚
sbit Fout=P1^7;			//发生频率管脚，可用单芯线将P1。7脚的频率输出连接P1。3的输入脚

/********数据定义*************************************************************/
code unsigned char table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40,0x00};//共阴数码管段值表 0-9 - 空 
unsigned char l_tmpdate[8];		//显示的缓冲区
bit int_flag;					//中断事件的响应
unsigned int fry;				//保存的频率值

/********函数声明*************************************************************/
void display(unsigned char *lp,unsigned char lc);//数字的显示函数；lp为指向数组的地址，lc为显示的个数
void delay(unsigned int timer);					//延时子函数
void Mee_F(void);								//测频函数
void Mee_T(void);								//测周函数
void Fry_Mee(void);								//测频测周选择


/***********主函数开始********************************************************/	
void main()
{ 
	unsigned int tmp;			//数据转换缓冲
	unsigned int i=2000;		//显示延时，提高亮度
 	EA=1;						//开总中断
 	TMOD=0x11; 					//定时器工作方式1
 	TH0=256-(50000/256);		//定时器初值
 	TL0=256-(50000%256);
 	TH1=256-500/256;
 	TL1=256-500%256;			
 	ET0=1;						//开定时器0 中断
 	ET1=1;						//开定时器1 中断
 	TR1=1;						//启动定时器1 

	while(1)    
 	{ 	
  	Fry_Mee(); 					//开始测量
	
	l_tmpdate[0]=fry/10000;		//测量完后将整型数分离出来，进行显示
	tmp=fry%10000;
	l_tmpdate[1]=tmp/1000;
	tmp=tmp%1000;
	l_tmpdate[2]=tmp/100;
	tmp=tmp%100;
	l_tmpdate[3]=tmp/10;
	l_tmpdate[4]=tmp%10;
	while(i--)					//显示延时
		display(l_tmpdate,5);	//显示频率
	i=2000;
 	}
}

/**********定时器0入口函数**************************************************/
void time0(void)  interrupt 1
{
	int_flag=1;					//中断标志
}

/**********定时器1入口函数**************************************************/
void time1(void)  interrupt 3 //定时器1的中断函数，我们用来产生频率
{
	TH1=256-1000/256; 			//重设初值
	TL1=256-1000%256;
	Fout=!Fout;					//取反 产生频率，也就是频率发生器，可改变计数值改变频率
}

/**********测频测周选择**************************************************/
void Fry_Mee(void)   
{
	if(fry<2000)  				//小于 2k 测周
		Mee_T();
	else if(fry>=2000) 			//大于2k 测频
		Mee_F();
}

/**********测频，原理：开一个标准的50ms计数中断，对被测信号计数**********/
void Mee_F(void)
{
 	bit lhj_old=1,lhj_new=1;		//定义状态
 	unsigned int f_count=0;   		//计数临时值
 	int_flag=0;
 	TH0=256-50000/256;				//定时器初值 50ms
 	TL0=256-50000%256;
 	TR0=1;							//启动计数器
 	while(1) 						//循环 测频
 	{
  		lhj_new=Fin;				//取得现在的 频率发生引脚状态
  		if(lhj_old!=lhj_new) 		//与前一个时刻 旧值 比较，如果不同
   		f_count++;					//则 计数加1
  		lhj_old=lhj_new; 			//将新值赋给旧值
 		if(int_flag)  				//如果到了定时时间
  		{	
   			TR0=0;					//关闭定时器0 
   			fry=f_count*10;			//计算频率,定时 50ms计数 每1个周期 计2次 所以 1s内计数= f_count*20/2=f_count*10
  			return;					//返回 跳出循环
  		}
 	}
}

/**********测周,原理：以被测信号的一个周期为中断源,读取定时器的值为计数值***************/
void Mee_T(void)
{ 
 	bit lhj_old=0,lhj_new=0; 		//定义状态
 	unsigned char temp_flag=0;
 	unsigned int t_count;   		//计数临时值
 
 	TH0=0;
 	TL0=0;
    while(1)						//循环 测周
    {
     	lhj_new=Fin; 				//取得现在的 频率发生引脚状态
        if(lhj_old&&!lhj_new)  		//下降沿开始启动定时器
        {
         	temp_flag++;   
         	TR0=1;  				//启动定时器 计数
        }
        if(temp_flag==2)			//两个下降沿的到来
        {
         	TR0=0;   				//计数停止
         	t_count=TH0*256+TL0;  	//取得当前的计数值
         	fry=1000000/t_count;  	//计算频率，这个1000000是晶振采用12M经12发频的计数脉冲
         	return;					//返回
        }
        lhj_old=lhj_new;
 }
}

/*************显示函数*******************************************/
void display(unsigned char *lp,unsigned char lc)
{
	unsigned char i;		//定义变量
	P2=0;					//端口2为输出
	P1=P1&0xF8;				//将P1口的前3位输出0，对应138译码器的输入脚，全0为第一位数码管
	for(i=0;i<lc;i++){		//循环显示
	P2=table[lp[i]];		//查表法得到要显示数字的数码段
	delay(10);				//短延时
	P2=0;					//清0端口，准备显示下位
	if(i==7)				//检测显示完8位否，完成直接退出，不让P1口再加1，否则进位影响到P13数据
		break;
	P1++;					//下一位数码管
	}
}

/*************延时子函数 *******************************************/
void delay(unsigned int timer)								
{
	while(timer--);
}
